// Greased MooTools:
// imported via manifest
// end Greased MooTools

var installPage = 'https://chrome.google.com/webstore/detail/beacpfphgdlmlhdgcpeemfemlnhgcjbi#';

['toString', 'toLocaleString', 'valueOf', 'toSource', 'watch', 'unwatch', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable'].each(function (method) {
	Class.Mutators[method] = $arguments(0);
});

// greasemonkey helpers and wrappers
// imported via manifest
// end greasemonkey helpers and wrappers

    var successIcon = 'http://l.yimg.com/g/images/icon_check_small.png';
    var errorIcon = 'http://l.yimg.com/g/images/icon_error_x_small.png';
    var images = {
	paypal: chrome.extension.getURL('images/paypal.png'),
	amazon: chrome.extension.getURL('images/amazon.png'),
	bitcoin: chrome.extension.getURL('images/bitcoin.png')
    }

// version check:
var backgroundPort = chrome.extension.connect({name: "flickrgrouppooltagchecker"});
backgroundPort.onMessage.addListener(function (msg) {
	if (msg.stat == 'error') {
		GM_log("ERROR: " + msg.statusText);
	}
	$(msg.callbackId).fireEvent(msg.callbackEvent, msg);
});

function getVersion(callbackId, callbackEvent) {
        try {
                backgroundPort.postMessage({ name: 'getVersion', callbackEvent: callbackEvent, callbackId: callbackId });
        } catch(e) {
                GM_log("ERROR connecting to the background page: " + e);
        }
}

function showUpdateNotification(data) {
	var onlineVersion = data.onlineVersion;
	var version = data.version;
	var beta = data.beta;

    var color = 'white';
    var updatespan = $('AlesaDams_updates_span');
    if (!$chk(updatespan)) {
    	updatespan = new Element('span', {
		id: 'AlesaDams_updates_span',
		// copied from Google++ userscript:
		styles: {
		    padding: '2px 4px',
		    display: 'block',
		    '-moz-background-clip': 'border',
		    '-moz-background-origin': 'padding',
		    '-moz-background-inline-policy': 'continuous',
		    position: 'fixed',
		    opacity: '0.7',
		    'z-index': 1011,
		    bottom: '5px',
		    right: '5px',
		    left: '5px'
		}
	    }).inject($(document).getElement("body"));
    }
    var bgColor = beta ? 'grey' : 'black';
    var updater = new Element('span', {
	styles: {
		background: bgColor + ' none repeat scroll 0% 0%',
		margin: '2px 5px',
		position: 'relative',
		'float': beta ? 'left' : 'right',
		opacity: beta ? '0.5' : ''
	}
    }).inject(updatespan);
    new Element('a', {
        html: 'FlickrGroupPoolTagChecker: ' + (beta ? 'beta v' + version : onlineVersion + ' available'),
	href: installPage,
        target: '_blank',
        title:  'to the ' + (beta ? 'stable version' : '') + ' install page (opens in new tab)',
        styles: {
            'color': color,
            'text-decoration': 'none'
        },
        events: {
            click: function () {
                GM_deleteValue("onlineVersion"); 
            }
        }
    }).inject(updater);
    new Element('a', {
        html: beta ? ' (feedback)' : ' (Changes)',
        title: 'opens in new tab',
        href: 'http://www.flickr.com/groups/flickrhacks/discuss/72157624324755123/',
        styles: {
            'text-decoration': 'none'
        },
        target: '_blank'
    }).inject(updater);
}

function getThreadInfo(data) {
        var threadId = data.threadId;
        var callback = data.callback;

        try {  
                new Request({
                        url: 'http://www.flickr.com',
                        onSuccess: function (responseText, responseXML) {
                                    try {
                                        var result;
                                        try {
                                            result = JSON.parse(responseText);
                                        } catch (e) {
						try {
							result = eval('(' + responseText + ')');
						} catch (f) {
	                    				GM_log("error parsing JSON reply for thread " + threadId + " (" + e + "): '" + responseText);
			    				callback({ threadId: threadId, success: false, message: e });
							return;
						}
                                        }
                                        if (result.stat === 'fail') {
                                                callback({ threadId: threadId, success: false, message: result.message });
                                        } else {
                                                callback({ threadId: threadId, success: true, message: result.topic.message._content });
                                        }
                                    } catch (e) {
                                        GM_log("ERROR processing result: " + e);
                                        callback({ threadId: threadId, success: false, message: "ERROR processing result: " + e });
                                    }
                                },
                                onFailure: function (response) {
                                        GM_log("error: " + response.statusText);
                                        callback({ threadId: threadId, success: false, message: response.statusText });
                                }
                }).get('/services/rest', {
                        api_key: GM_getMagisterLudi(),
                        auth_hash: GM_getAuthHash(),
                        auth_token: GM_getAuthToken(),
                        format: 'json',
                        method: 'flickr.groups.discuss.topics.getInfo',
                        nojsoncallback: 1,
                        topic_id: threadId
                });
        } catch (e) {
                callback({ threadId: threadId, success: false, message: 'Exception: ' + e });
        }
}

function checkVersion(version) {
  try {
    var lastVersionCheckTime = GM_getValue("lastVersionCheckTime");
    var onlineVersion = GM_getValue("onlineVersion");
    var elapsedtime;
    var CPStartTime = new Date();
    if ($chk(lastVersionCheckTime)) {
        elapsedtime = CPStartTime.getTime() - lastVersionCheckTime;
    }
    if (!lastVersionCheckTime || !onlineVersion || elapsedtime / 1000 > 60 * 60 * 12) { //more then 12h ago
    	getThreadInfo({ threadId: '72157624324755123', callback: function(retval) {
			var success = retval.success;
			var message = retval.message;
			if (!success) {
				GM_log("error getting version info: " + message);
				GM_deleteValue("onlineVersion");
				GM_deleteValue("lastVersionCheckTime");
				return;
			}
			var onlineVersion = message.split(/<i>current stable version:\s*/)[1].split(/<\/i>/)[0];
			GM_setValue("onlineVersion", onlineVersion);
        		GM_setValue("lastVersionCheckTime", (new Date()).getTime().toString());
		}
	});
    }

    if ($chk(onlineVersion)) {
        var updateAvailable = false;
        var reVersionMatch      = /(\d+)\.(\d+)\.(\d+)/;
        var onlineVersionParts  = reVersionMatch.exec(onlineVersion);
        var currentVersionParts = reVersionMatch.exec(version);
        var onlineVersionMajor, onlineVersionMinor, onlineVersionBuild;
        //[ onlineVersion, onlineVersionMajor, onlineVersionMinor, onlineVersionBuild ] = onlineVersionParts; 'invalid left-hand side' in Chrome
        onlineVersionMajor = onlineVersionParts[1];
        onlineVersionMinor = onlineVersionParts[2];
        onlineVersionBuild = onlineVersionParts[3];
        var currentVersionMajor, currentVersionMinor, currentVersionBuild;
        //[ currentVersion, currentVersionMajor, currentVersionMinor, currentVersionBuild] = currentVersionParts;
        currentVersionMajor = currentVersionParts[1];
        currentVersionMinor = currentVersionParts[2];
        currentVersionBuild = currentVersionParts[3];
        // first check major: important update! => rewrite, flickr updates, greasemonkey updates
        if (parseInt(onlineVersionMajor, 10) > parseInt(currentVersionMajor, 10)) {
            updateAvailable = true;
        } else if (parseInt(onlineVersionMajor, 10) === parseInt(currentVersionMajor, 10)) { // we don't want to downgrade
            // minor version update => new functionality
            if (parseInt(onlineVersionMinor, 10) > parseInt(currentVersionMinor, 10)) {
                updateAvailable = true;
            } else if (parseInt(onlineVersionMinor, 10) === parseInt(currentVersionMinor, 10)) { // we don't want to downgrade
                // build version update => bugfixes
                if (parseInt(onlineVersionBuild, 10) > parseInt(currentVersionBuild, 10)) {
                    updateAvailable = true;
                }
            }
        }
        if (updateAvailable) {
            showUpdateNotification({ onlineVersion: onlineVersion });
        } else if (version != onlineVersion) {  // not out of date, but different version => beta
		showUpdateNotification({ onlineVersion: onlineVersion, version: version, beta: true });
	}
    }
  } catch (e) {
    GM_log("checkVersion error: " + e);
  }
}

GM_addStyle('.FGPTC-tag-match { opacity: 0.1; }');
GM_addStyle('.FGPTC-tag-match-hidden { display: none; visibility: hidden; }');
GM_addStyle('div.FGPTC-photo-tag-enforcer { margin-top: 10px; display: block; }');

GM_deleteValue("FGPTC.preference.onlyAdmin");

var FGPTCPreferences = new Class({
    options: {
        rememberEnforceTag: true
    },
    initialize: function () {
        var storedRemember = GM_getValue("FGPTC.preference.rememberEnforceTag");
        if (storedRemember !== undefined) {
            this.options.rememberEnforceTag = storedRemember === true || storedRemember === 'true';
        }
    },
    rememberEnforceTag: function () {
        return this.options.rememberEnforceTag;
    },
    setRememberEnforceTag: function (b) {
        if (b !== this.options.rememberEnforceTag) {
            GM_setValue("FGPTC.preference.rememberEnforceTag", b);
            this.options.rememberEnforceTag = b;
            return true;
        }
        return false;
     }
});

function isGroupAdministratorOrModerator(groupname, groupId, userNsid, callback) {
    var callbackAlreadyCalled = false;
    var retval = GM_getValue("FGPTC.groupAdminOrMod." + groupname + "." + userNsid);
    if (retval != null && retval != undefined) {
    	callback({ success: true, adminOrMod: retval == true || retval == 'true' });
	callbackAlreadyCalled = true;
    }
    var lastReadTime = GM_getValue("FGPTC.groupAdminOrMod." + groupname + "." + userNsid + ".lastReadTime");
    var elapsedTime = $chk(lastReadTime) ? (new Date().getTime() - lastReadTime) : 24 * 60 * 60 * 1000 + 1;
    // run this test only once a day
    if (elapsedTime > 24 * 60 * 60 * 1000) {
	    var apiData = {
		    api_key: GM_getMagisterLudi(),
		    auth_hash: GM_getAuthHash(),
		    auth_token: GM_getAuthToken(),
		    format: 'json',
		    nojsoncallback: 1,
		    method: 'flickr.groups.members.getList',
		    group_id: groupId,
		    membertypes: '3,4',
		    per_page: 500 // one page should be sufficient?
	    };
	    new Request({
		    url: "http://www.flickr.com/",
		    onFailure: function (response) {
			GM_log("failed reading members from group: " + response.statusText);
			GM_deleteValue("FGPTC.groupAdminOrMod." + groupname + "." + userNsid + ".lastReadTime");
			GM_deleteValue("FGPTC.groupAdminOrMod." + groupname + "." + userNsid);
			if (!callbackAlreadyCalled) {
				callback({ success: false, message: response.statusText });
			}
		    },
		    onSuccess: function (responseText, responseXML) {
			var result;
			try {
			    result = JSON.parse(responseText);
			} catch (e) {
			    result = eval('(' + responseText + ')');
			}
			var adminOrMod = false;
			if (result.stat === 'fail') {
			    GM_log("failed reading members from group: " +result.code + " - " + result.message);
			    GM_deleteValue("FGPTC.groupAdminOrMod." + groupname + "." + userNsid + ".lastReadTime");
			    GM_deleteValue("FGPTC.groupAdminOrMod." + groupname + "." + userNsid);
			    if (!callbackAlreadyCalled) {
				callback({ success: false, message: result.message });
			    }
			    return;
			}
			var members = result.members;
			$each(members.member, function (member) {
			    if (member.nsid === userNsid) {
				adminOrMod = true;
			    }
			});
			GM_setValue("FGPTC.groupAdminOrMod." + groupname + "." + userNsid, adminOrMod);
			GM_setValue("FGPTC.groupAdminOrMod." + groupname + "." + userNsid + ".lastReadTime", 
				    new Date().getTime().toString());
			if (!callbackAlreadyCalled) {
				callback({ success: true, adminOrMod: adminOrMod });
			}
		    }
	    }).get("/services/rest", apiData);
    }
}

var username = GM_getLoggedInUser();
var user;
var userNsid = GM_getUserNsid();

    var CPStartTime = new Date();

//the real code
// *******************
// Start of processing
// *******************

function updateEnforcingTagsNumbers(selectedBoxes, idx, outcome) {
    selectedBoxes[idx] = outcome;
    $('FGPTC.success').set('html', selectedBoxes.filter(function(item) {
            return item == true;
        }).length
    );
    $('FGPTC.fail').set('html', selectedBoxes.filter(function(item) {
            return item == false;
        }).length
    );
    $('FGPTC.done').set('html', selectedBoxes.filter(function(item) {
            return item != undefined;
        }).length
    );
}

function addTags(photoId, tags, selectedBoxes, idx) {
    new Request({
        url: 'http://www.flickr.com', // use www. instead of api. => cross-site
        onSuccess: function (responseText, responseXML) {
        //GM_log("response: " + responseText);
            try {
                var retval;
                try {
                    retval = JSON.parse(responseText);//.replace(/^jsonFlickrApi\((.*)\)/, "$1"));
                } catch (e) { // JSON not defined !?
		    try {
		    	retval = eval('(' + responseText + ')');
		    } catch (f) {
                	GM_log("error parsing JSON reply for photo " + photoId + " (" + e + "): '" + responseText);
                	new Element('img', {
                		src: errorIcon,
                		title: e
			}).replaces($('FGPTC.spinner.' + photoId));
                	updateEnforcingTagsNumbers(selectedBoxes, idx, false);
                	return;
		    }
                }
                if (retval.stat === 'fail') {
                    new Element('img', {
                        src: errorIcon,
                        title: retval.message
                    }).replaces($('FGPTC.spinner.' + photoId));
                    updateEnforcingTagsNumbers(selectedBoxes, idx, false);
                    return;
                }
                new Element('img', {
                    src: successIcon
                }).replaces($('FGPTC.spinner.' + photoId));
            } catch (e) {
                new Element('img', {
                    src: errorIcon,
                    title: e
                }).replaces($('FGPTC.spinner.' + photoId));
                updateEnforcingTagsNumbers(selectedBoxes, idx, false);
            }
            updateEnforcingTagsNumbers(selectedBoxes, idx, true);
        },
        onFailure: function (response) {
            new Element('img', {
                src: errorIcon,
                title: "error: " + response.statusText,
            }).replaces($('FGPTC.spinner.' + photoId));
            updateEnforcingTagsNumbers(selectedBoxes, idx, false);
        }
    }).get('/services/rest', {
        api_key: GM_getMagisterLudi(),
        auth_hash: GM_getAuthHash(),
        auth_token: GM_getAuthToken(),
        format: 'json',
        nojsoncallback: 1,
        method: 'flickr.photos.addTags',
        photo_id: photoId,
        tags: tags
    });
}


function provideEnforcement() {
    	// add 'enfore tags', if not there yet
    	var enforceDiv = $('FGPTC.enforce_tag_div');
    	if(!$chk(enforceDiv)) {
        	enforceDiv = new Element('div', {
                        id: 'FGPTC.enforce_tag_div'
        	}).inject($('FGPTC.check-form'), 'bottom');
    	} else {
        	enforceDiv.empty();
    	}
        var enforceSmall = new Element('small').inject(enforceDiv);
        enforceSmall.adopt(
            new Element('span', {
                            html: '&emsp;enforce tag(s) '
            }),
            new Element('input', {
                            type: 'text',
                            name: 'enforced_tag',
                            value: preferences.rememberEnforceTag() ? GM_getValue(groupId + '.lastEnforcedTag') : '',
                            id: 'FGPTC.enforced_tag'
            }),
            new Element('span', {
                            html: ' on selected photos '
            }),
            new Element('span', {
                            html: '('
            }),
            new Element('input', {
                            type: 'checkbox',
                            id: 'FGPTC.select-all',
                            events: {
                                click: function (evt) {
                                    if (this.checked == true || this.checked == "true") {
                                        $$('input.FGPTC-tag-enforcer-checkbox').each(function(checkbox) {
                                            checkbox.checked = true;
                                        });
                                    }
                                }
                            }
            }),
            new Element('label', {
                            html: 'select all',
                            'for': 'FGPTC.select-all'
            }),
            new Element('span', {
                            html: ') '
            }),
            new Element('button', {
                html: 'enforce tag(s) on selected photos',
                events: {
                    click: function (evt) {
                        var tags = $('FGPTC.enforced_tag').value;
                        if (tags && tags.length > 0 && $('FGPTC.remember').checked) {
                            GM_setValue(groupId + '.lastEnforcedTag', tags);
                        }
                        preferences.setRememberEnforceTag($('FGPTC.remember').checked ? true : false);
                        var enforceDiv = $('FGPTC.enforce_tag_div');
                        enforceDiv.getElement('small').empty();
                        var selectedBoxes =  new Array($$('input.FGPTC-tag-enforcer-checkbox:checked').length);
                        enforceDiv.getElement('small').adopt(
                            new Element('label', {
                                            html: 'enforcing tag(s): '
                            }),
                            new Element('label', {
                                            html: '0',
                                            id: 'FGPTC.done'
                            }),
                            new Element('label', {
                                            html: ' of ' + selectedBoxes.length + ' photos - '
                            }),
                            new Element('label', {
                                            html: '0',
                                            id: 'FGPTC.success'
                            }),
                            new Element('label', {
                                            html: ' '
                            }),
                            new Element('img', {
                                            src: successIcon,
                                            height: 10
                            }),
                            new Element('label', {
                                            html: ' - '
                            }),
                            new Element('label', {
                                            html: '0',
                                            id: 'FGPTC.fail'
                            }),
                            new Element('label', {
                                            html: ' '
                            }),
                            new Element('img', {
                                            src: errorIcon,
                                            height: 10
                            })
                        );
                                  
                        $$('input.FGPTC-tag-enforcer-checkbox:checked').each(function(checkbox, idx) {
                                var photoId = checkbox.id.replace('FGPTC.checkbox.', '');
                                new Element('img', {
                                            src: 'http://www.flickr.com/images/pulser2.gif',
                                            id: 'FGPTC.spinner.' + photoId
                                }).replaces(checkbox);
                                addTags(photoId, tags, selectedBoxes, idx);
                            });
                    }
                }
            }),

                    new Element('br'),
                    new Element('span', {
                        html: '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'
                    }),
                    new Element('input', {
                        type: 'checkbox',
                        id: 'FGPTC.remember',
                        checked: preferences.rememberEnforceTag() ? 'checked' : '',
                        events: {
                            click: function (e) {
                                if ($('FGPTC.remember').checked) {
                                    if (!$chk($('FGPTC.enforced_tag').value)) {
                                        $('FGPTC.enforced_tag').set('value', GM_getValue(groupId + '.lastEnforcedTag'));
                                    }
                                }
                            }
                        }
                    }),
                    new Element('label', {
                        'for': 'FGPTC.remember',
                        'html': 'remember \'enforce tag(s)\''
                     })
        );
}

    if (window.name === 'Log page') {
       throw new Error("don't process log page");
    }

	new Element('span', {
		id: 'FGPTC-updatenotifier',
		styles: {
			display: 'none',
			visibility: 'hidden'
		},
		events: {
			'checkversion': function (evt) {
				checkVersion(evt.version);
				GM_setValue("FGPTC.version", evt.version);
    			}
		}
	}).inject($$('body')[0], 'bottom');
    	getVersion('FGPTC-updatenotifier', 'checkversion');


    var preferences = new FGPTCPreferences();

var checkTagsOnPhoto = function(photoId, photoSecret, tags, callback) {

    var apiData = {
            api_key: GM_getMagisterLudi(),
            auth_hash: GM_getAuthHash(),
            auth_token: GM_getAuthToken(),
            format: 'json',
            nojsoncallback: 1,
            method: 'flickr.photos.getInfo',
            photo_id: photoId,
	    secret: photoSecret
    };
    new Request({
            url: "http://www.flickr.com/",
            onFailure: function (response) {
                GM_log("failed retreiving info for photo '" + photoId + "': " + response.statusText);
		callback({ success: false, message: response.statusText });
            },
            onSuccess: function (responseText, responseXML) {
                var result;
                try {
                    result = JSON.parse(responseText);
                } catch (e) {
		    try {
		    	result = eval('(' + responseText + ')');
		    } catch (f) {
			    GM_log("error parsing JSON reply (" + e + "): '" + responseText);
			    callback({ success: false, message: e });
			    return;
		    }
                }
                retval = false;
                if (result.stat === 'fail') {
                    GM_log("failed API call: " + result.code + " - " + result.message);
                    callback({ success: false, message: result.code + ' - ' + result.message });
                    return;
                }
		if (!$chk(result.photo.tags) || !$chk(result.photo.tags.tag) || result.photo.tags.tag.length == 0) {
			// no tags
			callback({ success: true, matches: false });
			return;
		}
		if (!tags.contains('&')) {
			var matches = result.photo.tags.tag.some(function (photoTag) {
				return photoTag._content.test(tags);
			});
		} else {
			matches = tags.split('&').every(function (tag) {
				return result.photo.tags.tag.some(function (photoTag) {
					return photoTag._content.test(tag);
				})
			});
		}
		callback({ success: true, matches: matches });
            }
    }).get("/services/rest", apiData);

};

    if (document.location.href.match(/.*flickr.com\/groups\/[^\/]+/)) {
        var groupname = document.location.href.match(/.*flickr.com\/groups\/([^\/]+)/)[1];
        var groupId = GM_getGroupId();
        isGroupAdministratorOrModerator(groupname, groupId, userNsid, function(retval) {
            if (!retval.adminOrMod) {
                throw new Error("not an administrator/moderator for this group; aborting");
            }
	    if (!document.location.href.match('thumb=1')) {
		throw new Error("FlickrGroupPoolTagChecker will only run on the thumbnails view (add '?thumb=1' to the web address)");
	    }
		var photoList = $('pool-photos');
		if ($chk(photoList) && photoList.hasClass('photo-display-container')) {
		    var thumbs = photoList.getElements('span.photo_container');
		    if (!thumbs.every(function (thumb) { return thumb.hasClass('pc_t'); })) throw new Error("only run on 'small thumbnails' view");
		    var insertionPoint = photoList;
		    try {
			insertionPoint = $('photo-display-container'); // put it before the photos
		    } catch (e) {
			GM_log("layout changed?");
		    }
		    var checkForm = new Element('div', {
			id: 'FGPTC.check-form',
			styles: {
				background: '#DFDFDF',
				'-moz-border-radius': '1em',
				'-webkit-border-radius': '1em',
				'-khtml-border-radius': '1em',
				'border-radius': '1em',
				border: 'grey solid 1px',
				marginLeft: '20px',
				marginBottom: '10px',
				padding: '10px',
				display: 'inline-block',
				'min-width': '500px'
			}
		    }).inject(insertionPoint, 'before');
			
		    checkForm.adopt(new Element('div', { styles: { 'text-align': 'center' } }).adopt(
			new Element('span', {
				title: 'consider a donation',
				html: 'donate:',
				styles: {
					'float': 'left',
					'font-style': 'italic',
					'font-size': 'smaller',
					'vertical-align': 'middle'
				}
			}).adopt(
				new Element('a', {
					href: 'https://www.paypal.com/be/cgi-bin/webscr?cmd=_send-money&email=alesadam@ymail.com&amount_ccode=USD&payment_type=S',
					title: 'donate with Paypal',
					target: '_blank',
					styles: {
						margin: '1px'
					}
				}).adopt(
					new Element('img', { src: images.paypal, styles: { 'vertical-align': 'middle' } })
				),
				new Element('a', {
					href: 'http://www.amazon.co.uk/registry/wishlist/RWKOXV8NS09I/',
					title: 'buy me something from my Amazon wishlist (UK)',
					target: '_blank',
					styles: {
						margin: '1px'
					}
				}).adopt(
					new Element('img', { src: images.amazon, styles: { 'vertical-align': 'middle' } })
				),
				new Element('a', {
					href: 'http://www.amazon.com/gp/wishlist/2FWKY0A7NVSOJ/',
					title: 'buy me something from my Amazon wishlist (US)',
					target: '_blank',
					styles: {
						margin: '1px'
					}
				}).adopt(
					new Element('img', { src: images.amazon, styles: { 'vertical-align': 'middle' } })
				),
				new Element('a', {
					href: 'javascript:void(0);',
					title: 'donate Bitcoins',
					styles: {
						margin: '1px'
					},
					events: {
						click: function (evt) {
							// based on http://leo.bogert.de/2012/02/22/simple-bitcoin-donate-button/
							window.prompt ('Please copy-paste my Bitcoin address to your Bitcoin software - I cannot do it automatically.\nTo copy it, right-click the selected text and select \'Copy\'.\nThen right-click the address field in your Bitcoin software and select \'Paste\'.', '19DvtjDgiSx9991xVkXSYSovsSoreSGDC7');
						}
					}
				}).adopt(
					new Element('img', { src: images.bitcoin, styles: { 'vertical-align': 'middle' } })
				)
			),
			new Element('label', {
				html: 'FlickrGroupPoolTagChecker ',
				id: 'FGPTC.check-form-title',
				styles: {
					fontWeight: 'bold',
					display: 'inline-block',
					'float': 'center'
				},
				events: {
					'showversion': function(evt) {
						if (evt.stat == 'error') {
							new Element('img', {
								src: errorIcon,
								styles: {
									padding: '5px'
								}
							}).inject($(this), 'bottom');
							new Element('span', {
								html: "error reading version: " + msg.feedback,
								styles: {
									fontWeight: 'normal',
									color: 'red'
								}
							}).inject($(this), 'bottom');
						} else {
							var version = evt.version;
							new Element('span', { 
								html: 'v' + version,
								styles: {
									fontWeight: 'normal'
								}
							}).inject($(this), 'bottom');
						}
					}
				}
			}),
			new Element('a', {
				html: 'feedback thread',
				href: 'http://www.flickr.com/groups/flickrhacks/discuss/72157624324755123/',
				title: 'opens in new tab',
				target: '_blank',
				styles: {
					'float': 'right',
					'font-size': 'smaller',
					'font-style': 'italic',
					margin: 0
				}
			})
		    ));
		    new Element('hr', { styles: { width: '100%' } }).inject(checkForm);
		    getVersion('FGPTC.check-form-title', 'showversion');

		    var small = new Element('small').inject(checkForm);
		    small.adopt(
			new Element('span', {
			    html: 'check photos for missing tag(s) (regexp) '
			}),
			new Element('input', {
			    type: 'text',
			    id: 'FGPTC.required_tag',
			    value: GM_getValue(groupId + '.lastRequiredTag'),
			    name: 'tag'
			}),
			new Element('button', {
			    html: 'check',
			    id: 'FGPTC.check-button',
			    events: {
				click: function(evt) {
				
				    evt.preventDefault();
				    
				    // remove any checkboxes from the previous run
				    $$('div.FGPTC-photo-tag-enforcer').destroy();

				    var tagInput = $('FGPTC.required_tag');
				    if (tagInput.value && tagInput.value.length > 0) {
					GM_setValue(groupId + '.lastRequiredTag', tagInput.value);
				    }
				    tagInput.value = tagInput.value.replace(/[,\s\"!@#%\-_=\'\/;\`<>]/g, '').toLowerCase(); // remove some special chars
				    // show that we are busy
				    $('FGPTC.check-feedback-icon').fireEvent('notify-busy');
				    $('FGPTC.check-feedback').fireEvent('notify-busy');

				    var inProgress = [];
				    var successful = [];
				    var failure    = [];
				    var nPhotos = $$('div.pool-photo').length;
				    $$('div.pool-photo').each(function (photo) {
					var img = photo.getElements('img.pc_img')[0];
					var src = img.get('src');
					var photoId = src.match(/.*flickr.com\/\d+\/(\d+)_.*jpg/)[1];
					var photoSecret = src.match(/.*flickr.com\/\d+\/\d+_([\w\d]+)(?:_\w)?.jpg/)[1];
					inProgress.push(photoId);
					checkTagsOnPhoto(photoId, photoSecret, tagInput.value, function(retval) {
						inProgress.pop();
						if (retval.success == false) {
							failure.push(photoId);
							$('FGPTC.check-feedback-icon').fireEvent('notify-failure', retval.message);
							$('FGPTC.check-feedback').fireEvent('notify-failure', retval.message);
						} else {
							successful.push(photoId);
							if (retval.matches) {
								photo.addClass('FGPTC-tag-match');
								if ($('FGPTC.hide-matching').checked) {
									photo.addClass('FGPTC-tag-match-hidden');
								}
							} else {
								photo.adopt(
									new Element('div', {
										'class': 'FGPTC-photo-tag-enforcer'
									}).adopt(
										new Element('small').adopt(
										    new Element('input', {
											type: 'checkbox',
											id: 'FGPTC.checkbox.' + photoId,
											'class': 'FGPTC-tag-enforcer-checkbox'
										    }),
										    new Element('label', {
											html: 'enforce tag',
											'for': 'FGPTC.checkbox.' + photoId
										    })
										)
									)
								);
							}
						}
						if (inProgress.length == 0 && (successful.length + failure.length == nPhotos)) {
							$('FGPTC.check-feedback-icon').fireEvent('notify-done');
							$('FGPTC.check-feedback').fireEvent('notify-done');
							provideEnforcement();
						}	
					});
				    });
				
				}
			    }
			}),
			new Element('img', {
				id: 'FGPTC.check-feedback-icon',
				src: 'http://l.yimg.com/g/images/spaceout.gif',
				'class': 'FGPTC-ready',
				styles: {
					marginLeft: '10px',
					marginRight: '10px'
				},
				events: {
					'notify-busy': function (evt) {
						this.set('class', 'FGPTC-busy');
						this.set('src', 'http://www.flickr.com/images/pulser2.gif');
					},
					'notify-failure': function (evt) {
						this.set('class', 'FGPTC-error');
						this.set('src', errorIcon);
					},
					'notify-done': function (evt) {
						if (this.hasClass('FGPTC-busy')) {
							this.set('class', 'ready');
							this.set('src', successIcon);
						}
					}
				}
			}),
			new Element('span', {
				id: 'FGPTC.check-feedback',
				'class': 'FGPTC-ready',
				html: ' ',
				events: {
					'notify-busy': function (evt) {
						this.set('class', 'FGPTC-busy');
	//                            		this.set('html', '<i>Running checks. Please wait...</i>');
					},
					'notify-failure': function (evt) {
						if (this.hasClass('FGPTC-ready') || this.hasClass('FGPTC-busy')) {
							this.set('class', 'FGPTC-error');
							this.set('html', evt)
						} else if (this.hasClass('FGPTC-error')) {
							this.set('html', this.get('html') + ' - ' + evt);
						}
					},
					'notify-done': function (evt) {
						if (this.hasClass('FGPTC-busy')) {
							this.set('class', 'ready');
							this.set('html', ' ');
						}
					}
				}	
			})
		    );
		    new Element('br').inject(checkForm);
		    small = new Element('small').inject(checkForm);
		    small.adopt(
			new Element('span', {
			    html: '&emsp;&emsp;'
			}),
			new Element('input', {
				    type: 'checkbox',
				    id: 'FGPTC.hide-matching',
				    checked: GM_getValue(groupId + ".hideMatches") == true || GM_getValue(groupId + ".hideMatches") == "true",
				    events: {
					click: function (evt) {
					    GM_setValue(groupId + ".hideMatches", this.checked);
					    $$('div.FGPTC-tag-match').each(function(photo) {
						if (this.checked) {
							photo.addClass('FGPTC-tag-match-hidden');
						} else {
							photo.removeClass('FGPTC-tag-match-hidden');
						}
					    }, this);
					}
				    }
				}
			),
			new Element('label', {
				html: 'hide photos that have the required tag(s)',
				'for': 'FGPTC.hide-matching'
			})
		    )
		}
	});
    }

    // *******************
    //  End of processing
    // *******************



